/**
 * Created by GanJc on 2015/12/27.
 */

'use strict';

// 所有元素都大于0？
console.log(_.every([1, 4, 7, -3, -9], (x) => x > 0)); //false
// 至少一个元素大于0？
console.log(_.some([1, 4, 7, -3, -9], (x) => x > 0));// true

var arr = [2, 4, 6, 8];
console.log(_.first(arr));// 2
console.log(_.last(arr));// 8

//flatten()接收一个Array，无论这个Array里面嵌套了多少个Array，flatten()最后都把它们变成一个一维数组：
console.log(_.flatten([1, [2], [3, [[4], [5]]]])); // [1, 2, 3, 4, 5]

//zip()把两个或多个数组的所有元素按索引对齐，然后按索引合并成新数组。
//例如，你有一个Array保存了名字，另一个Array保存了分数，现在，要把名字和分数给对上，用zip()轻松实现：
var names = ['Adam', 'Lisa', 'Bart'];
var scores = [85, 92, 59];
console.log(_.zip(names, scores));
// [['Adam', 85], ['Lisa', 92], ['Bart', 59]]

var namesAndScores = [['Adam', 85], ['Lisa', 92,99], ['Bart', 59]];
console.log(_.unzip(namesAndScores));
// [['Adam', 'Lisa', 'Bart'], [85, 92, 59]]

var names = ['Adam', 'Lisa', 'Bart'];
var scores = [85, 92, 59];
console.log(_.object(names, scores));
// {Adam: 85, Lisa: 92, Bart: 59}


//range()让你快速生成一个序列，不再需要用for循环实现了：
// 从0开始小于10:
console.log(_.range(10)); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

// 从1开始小于11：
console.log(_.range(1, 11)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// 从0开始小于30，步长5:
console.log(_.range(0, 30, 5)); // [0, 5, 10, 15, 20, 25]

// 从0开始大于-10，步长-1:
console.log(_.range(0, -10, -1)); // [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]



console.log('Hello, world!');
// 输出'Hello, world!'

var log = console.log;
//log('Hello, world!');
// Uncaught TypeError: Illegal invocation

log.call(console,"hello!!");

log = _.bind(console.log,console);
log("hello world by bind");

log(Math.pow(3,10));

//如果我们不想固定第一个参数，想固定第二个参数怎么办？比如，
//希望创建一个偏函数cube(x)，计算x3，可以用_作占位符，固定住第二个参数：

var cube = _.partial(Math.pow,_,3);
log(cube(2));
log(cube(3));
log(cube(4));


//memoize
//如果一个函数调用开销很大，我们就可能希望能把结果缓存下来，以便后续调用时直接获得结果。举个例子，计算阶乘就比较耗时：

function factorial(n) {
    log('start calculate ' + n + '!...');
    var s = 1, i = n;
    while (i > 1) {
        s = s * i;
        i --;
    }
    log(n + '! = ' + s);
    return s;
}

factorial(10); // 3628800
// 注意控制台输出:
// start calculate 10!...
// 10! = 3628800

//用memoize()就可以自动缓存函数计算的结果：



var factorial = _.memoize(function(n) {
    console.log('start calculate ' + n + '!...');
    var s = 1, i = n;
    while (i > 1) {
        s = s * i;
        i --;
    }
    console.log(n + '! = ' + s);
    return s;
});

// 第一次调用:
factorial(10); // 3628800
// 注意控制台输出:
// start calculate 10!...
// 10! = 3628800

// 第二次调用:
factorial(10); // 3628800
// 控制台没有输出


var factorial = _.memoize(function(n) {
    console.log('start calculate ' + n + '!...');
    if (n < 2) {
        return 1;
    }
    return n * factorial(n - 1);
});

factorial(10); // 3628800
// 输出结果说明factorial(1)~factorial(10)都已经缓存了:

log(factorial(9)); // 362880
// console无输出

var register = _.once(function () {
    log('Register ok!');
});

// 测试效果:
register();
register();
register();

//delay()可以让一个函数延迟执行，效果和setTimeout()是一样的，但是代码明显简单了：
// 2秒后调用alert():
_.delay(log, 2000,"delay 2000");

function Student(name, age) {
    this.name = name;
    this.age = age;
}
Student.prototype.school = 'No.1 Middle School';
var xiaoming = new Student('小明', 20);
log(_.keys(xiaoming)); // ['name', 'age']
//allKeys()除了object自身的key，还包含从原型链继承下来的：
log(_.allKeys(xiaoming)); // ['name', 'age']
log(_.values(xiaoming)); // ['name', 'age']


//mapObject
//mapObject()就是针对object的map版本：
var obj = { a: 1, b: 2, c: 3 };
// 注意传入的函数签名，value在前，key在后:
log(_.mapObject(obj, (v, k) => 100 + v)); // { a: 101, b: 102, c: 103 }


//invert 把object的每个key-value来个交换，key变成value，value变成key：

var obj = {
    Adam: 90,
    Lisa: 85,
    Bart: 59
};
log(_.invert(obj)); // { '59': 'Bart', '85': 'Lisa', '90': 'Adam' }

//extend()把多个object的key-value合并到第一个object并返回：
var a = {name: 'Bob', age: 20};
_.extend(a, {age: 15}, {age: 11111, city: 'Beijing'}); // {name: 'Bob', age: 88, city: 'Beijing'}
// 变量a的内容也改变了：
log(a); // {name: 'Bob', age: 88, city: 'Beijing'}

//如果我们要复制一个object对象，就可以用clone()方法，它会把原有对象的所有属性都复制到新的对象中：
var source = {
    name: '小明',
    age: 20,
    skills: ['JavaScript', 'CSS', 'HTML']
};

var copied = _.clone(source);
log(JSON.stringify(copied, null, '  '));
log(source.skills === copied.skills);

//isEqual()对两个object进行深度比较，如果内容完全相同，则返回true：
var o1 = { name: 'Bob', skills: { Java: 90, JavaScript: 99 }};
var o2 = { name: 'Bob', skills: { JavaScript: 99, Java: 90 }};

log(o1 === o2); // false
log(_.isEqual(o1, o2)); // true


var o1 = ['Bob', { skills: ['Java', 'JavaScript'] }];
var o2 = ['Bob', { skills: ['Java', 'JavaScript'] }];

log(o1 === o2); // false
log(_.isEqual(o1, o2)); // true

// unserscore 的链式写法
log(_.filter(_.map([1, 4, 9, 16, 25], Math.sqrt), x => x % 2 === 1));

log(_.chain([1, 4, 9, 16, 25])
    .map(Math.sqrt)
    .filter(x => x % 2 === 1)
    .value())
